use crate::duck;
use crate::error::AppError;
use crate::models::datasource as ds_model;
use crate::routes::handler::RouteHandler;
use crate::routes::payload::Payload;
use crate::routes::response::Response;
use crate::schemas::base::{
    FilterFunc, FilterItem, FilterValue, ListResult, OneEffect, OneResultId,
};
use crate::schemas::datasource::DescriptionItem;
use crate::schemas::duck::FieldItem;
use crate::{convert_vec, db, extract_payload, schemas};
use async_trait::async_trait;
use sea_orm::Set;

pub struct CreateDsFile;

#[async_trait]
impl RouteHandler for CreateDsFile {
    async fn handle(&self, payload: Payload) -> Result<Response, AppError> {
        let data = extract_payload!(payload, Payload::CreateDsFile)?;
        // 插入 ds_core 对象
        let datasource: ds_model::core::ActiveModel = data.clone().into();
        let new_datasource = db::create::one("project", datasource).await?;
        // 插入 ds_file 对象
        let mut ds_file: ds_model::file::ActiveModel = data.into();
        ds_file.ds_id = Set(new_datasource.id.clone());
        db::create::one("project", ds_file).await?;
        // 返回ds对象
        let new_datasource: schemas::datasource::ListItem = new_datasource.into();
        Ok(Response::DatasourceEffect(OneEffect {
            effect: new_datasource,
        }))
    }
}

pub struct CreateDsServe;

#[async_trait]
impl RouteHandler for CreateDsServe {
    async fn handle(&self, payload: Payload) -> Result<Response, AppError> {
        let data = extract_payload!(payload, Payload::CreateDsServe)?;
        // 插入 ds_core 对象
        let datasource: ds_model::core::ActiveModel = data.clone().into();
        let new_datasource = db::create::one("project", datasource).await?;
        // 插入 ds_serve 对象
        let mut ds_serve: ds_model::serve::ActiveModel = data.into();
        ds_serve.ds_id = Set(new_datasource.id.clone());
        db::create::one("project", ds_serve).await?;
        // 返回ds对象
        let new_datasource: schemas::datasource::ListItem = new_datasource.into();
        Ok(Response::DatasourceEffect(OneEffect {
            effect: new_datasource,
        }))
    }
}

pub struct ListDatasource;

#[async_trait]
impl RouteHandler for ListDatasource {
    async fn handle(&self, payload: Payload) -> Result<Response, AppError> {
        let query = extract_payload!(payload, Payload::ListQuery)?;
        let ds_list =
            db::read::list::<ds_model::core::Entity, ds_model::core::Model>("project", query)
                .await?;
        let result: Vec<schemas::datasource::ListItem> = convert_vec!(ds_list.result);
        Ok(Response::ListDatasource(ListResult {
            total: ds_list.total,
            result,
        }))
    }
}

pub struct UpdateDsFile;
#[async_trait]
impl RouteHandler for UpdateDsFile {
    async fn handle(&self, payload: Payload) -> Result<Response, AppError> {
        let data = extract_payload!(payload, Payload::UpdateDsFile)?;
        // 更新 core 表
        let mut datasource: ds_model::core::ActiveModel = data.clone().into();
        datasource.id = Set(data.ds_id.clone());
        db::update::by_id("project", datasource.clone(), data.ds_id.clone()).await?;
        // 更新 file 表
        let ds_file: ds_model::file::ActiveModel = data.clone().into();
        let result = db::update::by_id("project", ds_file.clone(), data.id.clone()).await?;
        // 返回结果
        Ok(Response::OneResultId(OneResultId { id: result }))
    }
}

pub struct UpdateDsServe;
#[async_trait]
impl RouteHandler for UpdateDsServe {
    async fn handle(&self, payload: Payload) -> Result<Response, AppError> {
        let data = extract_payload!(payload, Payload::UpdateDsServe)?;
        // 更新 core 表
        let mut datasource: ds_model::core::ActiveModel = data.clone().into();
        datasource.id = Set(data.ds_id.clone());
        db::update::by_id("project", datasource.clone(), data.ds_id.clone()).await?;
        // 更新 file 表
        let ds_file: ds_model::serve::ActiveModel = data.clone().into();
        let result = db::update::by_id("project", ds_file.clone(), data.id.clone()).await?;
        // 返回结果
        Ok(Response::OneResultId(OneResultId { id: result }))
    }
}

pub struct AllDsDesc;

#[async_trait]
impl RouteHandler for AllDsDesc {
    async fn handle(&self, payload: Payload) -> Result<Response, AppError> {
        let data = extract_payload!(payload, Payload::OperateDatasource)?;

        // 获取所有字段信息
        let all_fields = duck::read::field_all(&data.id)?;

        // 查询已有的描述信息
        let all_desc = db::read::all_by_filter::<ds_model::description::Entity>(
            "project",
            Some(vec![FilterItem {
                field: "ds_id".to_string(),
                func: FilterFunc::EQ,
                value: Some(FilterValue::String(data.id.clone())),
            }]),
        )
        .await?;

        // 遍历比对合并
        let mut results: Vec<DescriptionItem> = Vec::new();

        for field in all_fields {
            let mut result = DescriptionItem {
                ds_id: data.id.clone(),
                field_name: field.column_name.clone(),
                data_type: field.data_type.clone(),
                nullable: field.nullable == "YES".to_string(),
                ..Default::default()
            };
            let desc = all_desc.iter().find(|d| d.field_name == field.column_name);
            match desc {
                Some(d) => {
                    result.id = Some(d.id.clone());
                    result.comment = Some(d.comment.clone());
                    result.description = Some(d.description.clone())
                }
                None => {}
            }
            results.push(result);
        }

        Ok(Response::DsDesc(results))
    }
}

pub struct CreateDsDesc;

#[async_trait]
impl RouteHandler for CreateDsDesc {
    async fn handle(&self, payload: Payload) -> Result<Response, AppError> {
        let data = extract_payload!(payload, Payload::CreateDsDescription)?;
        // 插入 ds_core 对象
        let data: ds_model::description::ActiveModel = data.clone().into();
        let new_data = db::create::one("project", data).await?;
        Ok(Response::OneResultId(OneResultId {
            id: new_data.id.clone(),
        }))
    }
}
